package com.jwork.progress.config.aop;

import com.jwork.progress.config.annotation.SystemLog;
import com.jwork.progress.pojo.entity.SystemLogEntity;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

@Order(2)
@Component
@Aspect
public class SystemLogAspect {
    /**
     * 定义切入点，切入所有标注此注解的类和方法
     */
    @Pointcut("@within(com.jwork.progress.config.annotation.SystemLog)|| @annotation(com.jwork.progress.config.annotation.SystemLog)")
    public void methodAdvice() {
    }

    /**
     * 方法环绕通知
     */
    @Around(value = "methodAdvice()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        // 记录请求日志
        SystemLogEntity logEntity = buildSystemLogEntity(joinPoint);
        try {
            // 执行目标方法
            return joinPoint.proceed();
        } catch (Throwable throwable) {
            logEntity.setResult(false);
            logEntity.setMessage(throwable.getMessage());
            throw throwable;
        } finally {
            System.out.println("代理-> 来自Around环绕通知，请求日志：" + logEntity.toString());
        }
    }

    /**
     * 封装日志请求
     * @param joinPoint
     * @return
     * @throws Exception
     */
    private SystemLogEntity buildSystemLogEntity(ProceedingJoinPoint joinPoint) throws Exception {
        // 获取目标类名
        String targetName = joinPoint.getTarget().getClass().getSimpleName();
        // 获取目标方法
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        // 获取目标请求参数值
        Object[] args = joinPoint.getArgs();
        // 获取目标方法上的注解配置
        SystemLog systemLog = getSystemLogConfig(method);

        // 封装系统日志信息
        SystemLogEntity logEntity = new SystemLogEntity();
        logEntity.setClassName(targetName);
        logEntity.setMethodName(method.getName());
        logEntity.setParam(getParametersLog(methodSignature, args));
        logEntity.setResult(true);
        logEntity.setDesc(systemLog.desc());
        return logEntity;
    }

    /**
     * 获取类或者方法上的注解配置
     * @param method
     * @return
     */
    private SystemLog getSystemLogConfig(Method method) {
        // 优先从方法上获取目标注解
        if (method.isAnnotationPresent(SystemLog.class)) {
            return method.getAnnotation(SystemLog.class);
        }
        // 如果方法上找不到，则从类上获取注解
        Class<?> declaringClass = method.getDeclaringClass();
        return declaringClass.getAnnotation(SystemLog.class);
    }

    /**
     * 获取请求参数详情
     * @param args
     * @return
     */
    private String getParametersLog(MethodSignature methodSignature, Object[] args) {
        // 获取参数名称
        String[] parameterNames = methodSignature.getParameterNames();
        StringBuilder stringBuilder = new StringBuilder();
        if (parameterNames != null && parameterNames.length > 0) {
            for (int i = 0; i < parameterNames.length; i++) {
                stringBuilder.append(parameterNames[i])
                        .append(":")
                        .append(args[i])
                        .append(";");
            }
        }
        return stringBuilder.toString();
    }
}
